package com.open.basic.util;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.objenesis.strategy.StdInstantiatorStrategy;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;


/**
 * @author system
 * @Date 2023/12/3 11:54
 * @description KryoUtil工具类
 */
public class KryoUtil {

    static List<String> registeredClasses = new ArrayList<>();
    private static final ThreadLocal<Kryo> THREAD_LOCAL = new ThreadLocal<Kryo>() {
        @Override
        protected Kryo initialValue() {
            Kryo kryo = new Kryo();
            // 对象引用 开启用时间换空间 关闭占用更多内存，但会提高序列化速度
            kryo.setReferences(false);
            // 设置初始化策略，如果没有默认无参构造器，那么就需要设置此项,使用此策略构造一个无参构造器
            kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
            // 设置是否注册全限定名，关闭序列化注册，会导致性能些许下降，但在分布式环境中，注册类生成ID不一致会导致错误
            kryo.setRegistrationRequired(false);
            // 常用类注册
            registeredClasses.forEach(className -> {
                try {
                    kryo.register(Class.forName(className));
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            });
            // 设置类加载器为线程上下文类加载器（如果Processor来源于容器，必须使用容器的类加载器，否则妥妥的CNF）
            kryo.setClassLoader(Thread.currentThread().getContextClassLoader());
            return kryo;
        }
    };

    static {
        // 读取classpath下的kryo.register.txt文件
        try {
            File file = new File(KryoUtil.class.getResource("/kryo.register.txt").toURI());
            if (file.exists()) {
                BufferedReader reader = new BufferedReader(new FileReader(file));

                String line = null;
                while ((line = reader.readLine()) != null) {
                    registeredClasses.add(line);
                }
            }
        } catch (Exception e) {
        }
    }

    /**
     * 1024字节， 默认1M
     */
    private static final int DEFAULT_BUFFER_SIZE = 1024;
    /**
     * 大对象  不能超过100M
     */
    private static final int DEFAULT_MAX_BUFFER_SIZE = 1024 * 100;

    private KryoUtil() {

    }


    public static byte[] serialize(Object obj) {
        Kryo kryo = THREAD_LOCAL.get();
        // 需不需要注册类
//        kryo.register(obj.getClass());
        Output output = new Output(DEFAULT_BUFFER_SIZE, DEFAULT_MAX_BUFFER_SIZE);
        kryo.writeObject(output, obj);
        output.close();
        return output.toBytes();
    }

    public static <T> T deserialize(byte[] bytes, Class<T> clazz) {
        Kryo kryo = THREAD_LOCAL.get();
//        kryo.register(clazz);
        Input input = new Input(bytes);
        T obj = kryo.readObject(input, clazz);
        input.close();
        return obj;
    }
}
